
/* GCSx
** GRAPHICS.H
**
** Basic graphics primitives/support via SDL
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#ifndef __GCSx_GRAPHICS_H_
#define __GCSx_GRAPHICS_H_

// Startup/exit
void initVideo();
// -1 for "best" bpp; gl mode disallows any direct access to screen surface
void selectVideoMode(int x, int y, int bpp, int fullscreen, int resizable, int gl = 0) throw_Video;
void exitVideo();
void prepareFont();
void closeFont();

// GUI colors, in RGB and packed formats
enum {
    COLOR_FILL = 0,
    COLOR_LIGHT1,
    COLOR_LIGHT2,
    COLOR_DARK1,
    COLOR_DARK2,
    COLOR_BUTTONFILL1,
    COLOR_BUTTONFILL2,
    COLOR_BUTTONDOWN1,
    COLOR_BUTTONDOWN2,
    COLOR_TEXT,
    COLOR_TITLEACTIVE1,
    COLOR_TITLEACTIVE2,
    COLOR_TITLEINACTIVE1,
    COLOR_TITLEINACTIVE2,
    COLOR_TEXTBOX,
    COLOR_CURSOR,
    COLOR_SELECTION1,
    COLOR_SELECTION2,
    COLOR_TILECURSOR,
    COLOR_TILESELECTION,
    COLOR_TILECURSORBORDER1,
    COLOR_TILECURSORBORDER2,
    COLOR_SCROLLTRACK,
    COLOR_LINEBORDER,
    COLOR_BKFILL,
    COLOR_GRID,
    COLOR_FRONTDESKTOP,
    COLOR_EDITORDESKTOP,
    COLOR_TRANSPARENT1,
    COLOR_TRANSPARENT2,
    COLOR_TOOLTIP,
    COLOR_GLYPHWIDTH,
    COLOR_POPUPFILL1,
    COLOR_POPUPFILL2,
    COLOR_POPUPTEXT,
    COLOR_CONSOLEPROMPT,
    COLOR_CONSOLEINPUT,
    COLOR_COUNT
};

extern SDL_Color guiRGB[COLOR_COUNT];
extern Uint32 guiPacked[COLOR_COUNT];

// For gui- removes first \t and returns an underline position/length code
// Places shortcut key (lowercase) in shortcut if not NULL
int convertGuiText(std::string* text, char* shortcut, int font = FONT_STANDARD);
// Draws the underline, call after drawText
void drawTextUnderline(int underlineCode, Uint32 color, int x, int y, SDL_Surface* surface, int font = FONT_STANDARD);

// Radio buttons and checkboxes
void drawCheckbox(int isRadio, int isChecked, int isDisabled, int x, int y, int size, SDL_Surface* surface);

// Info
int fontWidth(const std::string& text, int font = FONT_STANDARD);
int fontHeight(int font = FONT_STANDARD);
int fontAscent(int font = FONT_STANDARD);
extern int screenWidth;
extern int screenHeight;
int screenBits();
int screenFullscreen();
int screenResizable();
int screenGL();
int guiOk(); // True if GUI is usable- used by exceptions

// Rectangle operations
// Intersection of two rects; returns false and sets a.w to 0 if empty
// intersection; result in a
int intersectRects(Rect& a, const Rect& b);
// Bounding box around two rects; result in a
// Special case returns a untouched if b.w is zero, returns b in a if a.w is zero
// If both .w are zero, false is returned with a unchanged
// True is returned otherwise
int boundRects(Rect& a, const Rect& b);
// Take x1/x2/y1/y2 and create a rectangle; swaps as needed
Rect createRect(int x1, int y1, int x2, int y2);

// Used in GL mode only- only needed if you're doing your own stuff
// However, if you use one, you must use the other
void preGLScreenFlip();
// (then do your drawing, then optionally call screenFlip, then optionally do additional drawing)
void postGLScreenFlip();
// (calling postGLScreenFlip has no effect if you didn't use preGLScreenFlip)

// Standard graphics primitives/functions
void screenFlip(const Rect* area = NULL); // area.w 0 for mouse-only update
void setScreenGLAlpha(int alpha); // Only works in GL mode- alpha blends screen; 0-256
void drawPixel(int x, int y, SDL_Color color, SDL_Surface* surface);
void drawPixel(int x, int y, Uint32 data, SDL_Surface* surface);
// Returns alpha 0 black if outside clip area
Uint32 getPixel(int x, int y, SDL_Surface* surface);

// (to allow common SDL routins with our Rect structure)
// (doesn't support NULL rect mode!)
int SDL_FillRect(SDL_Surface *dst, Rect *dstrect, Uint32 color);
void SDL_SetClipRect(SDL_Surface *surface, Rect *rect);
void SDL_SetClipRect(SDL_Surface *surface, const Rect *rect);

void blit(int sX, int sY, SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width = -1, int height = -1);
// (returns width)
int drawText(const std::string& text, SDL_Color fg, int x, int y, SDL_Surface* surface, int font = FONT_STANDARD);
void drawRect(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface);
void drawGradient(int x, int y, int w, int h, SDL_Color color1, SDL_Color color2, SDL_Surface* surface);
void drawBox(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface);
void drawLine(int x1, int y1, int x2, int y2, Uint32 color, SDL_Surface* surface);
// (x1 can be > or < x2)
void drawHLine(int x1, int x2, int y1, Uint32 color, SDL_Surface* surface);
void drawVLine(int y1, int y2, int x1, Uint32 color, SDL_Surface* surface);
// (dotted lines automatically line up wherever drawn)
void drawDottedHLine(int x1, int x2, int y, Uint32 color, SDL_Surface* surface);
void drawDottedVLine(int y1, int y2, int x, Uint32 color, SDL_Surface* surface);
void drawGuiBox(int x, int y, int w, int h, int thickness, SDL_Surface* surface);
// (inverted version does not prefill with solid color!)
void drawGuiBoxInvert(int x, int y, int w, int h, int thickness, SDL_Surface* surface);
void drawFocusBox(int x, int y, int w, int h, SDL_Surface* surface);
void drawSelectRect(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface, int alpha = 128);
// (unused)
// void drawSelectGradient(int x, int y, int w, int h, SDL_Color color1, SDL_Color color2, SDL_Surface* surface, int alpha = 128);

// phase ranges from 0 to 3; this is used to draw selection rectangles in a
// style similar to "walking ants"; the black portion of rectangle is drawn
// with 0 alpha also, so be careful if alpha blitting
enum { NUM_PHASES = 8 };
void drawAntsHLine(int x1, int x2, int y, int phase, SDL_Surface* surface);
void drawAntsVLine(int y1, int y2, int x, int phase, SDL_Surface* surface);
void drawAntsBox(int x1, int y1, int w, int h, int phase, SDL_Surface* surface);

// Creating surfaces
// (software surface, same settings as screen, alpha blending disabled by default)
SDL_Surface* createSurface(int width, int height);
// (software surface, 32bpp, RGBA order, alpha blending disabled by default)
SDL_Surface* createSurface32(int width, int height);
// (software surface, 8bpp, for creating masks and such, not intended for actual video)
SDL_Surface* createSurface8(int width, int height);
// (performs a full alpha-overlay designed for graphics editing; unoptimized;
//  assumes both surfaces are from createSurface32)
void alphaBlit32(int sX, int sY, const SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width = -1, int height = -1);
// For graphics display in editor (fairly unoptimized) assumes src is createSurface32
// rgba are on specified scales; asserts w=h if using rotate90
void alphaBlitFx(int sX, int sY, const SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width = -1, int height = -1, int mirror = 0, int flip = 0, int rotate90 = 0, int red = 0xFF, int green = 0xFF, int blue = 0xFF, int rgbScale = 0xFF, int alpha = 0xFF, int alphaScale = 0xFF);
// (performs a blit from one surface to another, masked by a third; 0 alpha on third
//  means don't copy anything, anything else means copy exactly; target surface,
//  mask surface, and source surface can be the same IF the x/y are the same)
// (if clear is true, fills any spot where copy was performed with the clear color)
void maskBlit32(int sX, int sY, SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int mX, int mY, const SDL_Surface* mask, int width = -1, int height = -1, int clear = 0, Uint32 clearColor = 0);
void maskAlphaBlit32(int sX, int sY, SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int mX, int mY, const SDL_Surface* mask, int alphaPercent = 100, int width = -1, int height = -1, int clear = 0, Uint32 clearColor = 0);

// For use specifically with createSurface32 surfaces only
inline Uint32 mapColor32(int r, int g, int b, int a) {
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    return (r << 24) | (g << 16) | (b << 8) | a;
#else
    return (a << 24) | (b << 16) | (g << 8) | r;
#endif
}
inline void splitColor32(Uint32 color, int& r, int& g, int& b, int& a) {
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    a = color & 255;
    b = (color >> 8) & 255;
    g = (color >> 16) & 255;
    r = (color >> 24) & 255;
#else
    r = color & 255;
    g = (color >> 8) & 255;
    b = (color >> 16) & 255;
    a = (color >> 24) & 255;
#endif
}

// Flood fill
// Only works on surface32s
// Returns affected area
// Relies on using color on *dest as a boundary for what's already been filled.
// This means dest must be empty (or not use color) OR, dest can be the same as
// src IF tolerance is zero. If you use dest/src the same and tolerance is not
// zero, the fill will stop if the filled area already contains color; if you use
// a separate dest that already contains the color, it will prohibit filling.
Rect floodFill32(SDL_Surface* src, SDL_Surface* dest, int x, int y, Uint32 color, int tolerance);
// Non-contiguous fill- no special exceptions needed
Rect floodFillNonContiguous32(SDL_Surface* src, SDL_Surface* dest, int x, int y, Uint32 color, int tolerance);

// Lower level functions that may be of use (returns NULL if createText called with empty string)
SDL_Surface* createText(const std::string& text, SDL_Color fg, int alpha = 1, int font = FONT_STANDARD);
SDL_Surface* getScreen();
Uint32 convertRGB(SDL_Color color, int alpha = -1);
// (called whenever palette/mode changes)
void convertGuiItems();

enum {
    // Mouse pointers
    MOUSE_NORMAL = 0,
    MOUSE_VERT,
    MOUSE_HORIZ,
    MOUSE_BEAM,
    MOUSE_DIAGDOWN,
    MOUSE_DIAGUP,
    MOUSE_PIXEL,
    MOUSE_ADD,
    MOUSE_SUBTRACT,
    MOUSE_FOURDIRECTION,
    MOUSE_COUNT,
};

void selectMouse(int type);
int mouseTooltipYOffset(); // Pixels to offset tooltip by for current mouse
// low level, called by gui; always call unblit before blit if both called
void unblitMouse(); // only call once before screenupdate
void blitMouse(); // only call once before screenupdate

#endif

